package com.liaojp.cmsweb.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liaojp.cmsweb.Result.AjaxResult;
import com.liaojp.cmsweb.domain.Role;
import com.liaojp.cmsweb.domain.User;
import com.liaojp.cmsweb.domain.UserRole;
import com.liaojp.cmsweb.exception.ErrorPasswordException;
import com.liaojp.cmsweb.httpParam.user.LoginParam;
import com.liaojp.cmsweb.httpParam.user.RegisterParam;
import com.liaojp.cmsweb.mapper.RoleMapper;
import com.liaojp.cmsweb.mapper.UserRoleMapper;
import com.liaojp.cmsweb.service.RoleService;
import com.liaojp.cmsweb.service.UserRoleService;
import com.liaojp.cmsweb.service.UserService;
import com.liaojp.cmsweb.mapper.UserMapper;
import com.liaojp.cmsweb.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
* @author 廖家鹏
* @description 针对表【user】的数据库操作Service实现
* @createDate 2025-04-24 22:10:57
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{
    private final PasswordEncoder passwordEncoder;

    @Value("${my.admin.enable}")
    private boolean adminEnable = false;

    @Value("${my.admin.username}")
    private String username = "";

    @Value("${my.admin.password}")
    private String password = "";

    private final JwtTokenUtil jwtTokenUtil;
    private final RoleService roleService;
    private final UserRoleService userRoleService;
    private final UserDetailsService userDetailsService;

    public UserServiceImpl(PasswordEncoder passwordEncoder, JwtTokenUtil jwtTokenUtil, UserRoleMapper userRoleMapper, RoleService roleService, UserRoleService userRoleService, UserDetailsService userDetailsService) {
        this.passwordEncoder = passwordEncoder;
        this.jwtTokenUtil = jwtTokenUtil;
        this.roleService = roleService;
        this.userRoleService = userRoleService;
        this.userDetailsService = userDetailsService;
    }

    /**
     * 不使用Spring Security的登录
     * @param loginParam 登录参数
     * @return AjaxResult
     */
    public AjaxResult loginBack(LoginParam loginParam) {
        String usernameParam = loginParam.getUsername();
        String passwordParam = loginParam.getPassword();

        //验证用户名 密码格式
        boolean format = checkFormat(loginParam.getUsername(), loginParam.getPassword());
        if (!format){
            return AjaxResult.error(1, "用户名或密码格式错误");
        }



        // 是否是admin
        if (adminEnable){
            if (username.equals(loginParam.getUsername()) && password.equals(loginParam.getPassword())){
                // 生成token
                String token = jwtTokenUtil.generateToken("admin");

                return AjaxResult.success("登录成功", token);
            }
        }

        // 查询数据库验证密码
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(User::getUsername, usernameParam);
        User user = getOne(queryWrapper);
        if (user == null){
            return AjaxResult.error(2, "用户名不存在");
        }
        if (!passwordEncoder.matches(passwordParam, user.getPasswordBcrypt())){
            return AjaxResult.error(2, "用户名或密码错误");
        }

        // 生成token
        String token = jwtTokenUtil.generateToken(user.getUsername());

        return AjaxResult.success(token);
    }

    @Override
    public AjaxResult login(LoginParam loginParam) {
        // 从数据库获取用户信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(loginParam.getUsername());

        // 校验密码
        if (!passwordEncoder.matches(loginParam.getPassword(), userDetails.getPassword())){
            throw new ErrorPasswordException("用户名或密码错误");
        }

        // 创建Authentication对象并放入安全上下文中
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(loginParam.getUsername(), loginParam.getPassword());
        SecurityContextHolder.getContext().setAuthentication(authentication);

        // 生成token返回给前端
        String token = jwtTokenUtil.generateToken(loginParam.getUsername());

        return AjaxResult.success(token);
    }

    @Override
    @Transactional
    // todo 测试事务：1、不加事务的情况；2、事务传播行为；3、事务隔离级别
    public AjaxResult register(RegisterParam registerParam) {
        // 验证参数
        if (registerParam == null || registerParam.getUsername() == null || registerParam.getPassword() == null){
            return AjaxResult.error(1, "注册参数不能为空");
        }

        if (registerParam.getUsername().isEmpty() || registerParam.getPassword().isEmpty()){
            return AjaxResult.error(3, "用户名或密码不能为空");
        }

        // todo 验证"  "多个空格的情况

        // 验证是否已存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(User::getUsername, registerParam.getUsername());
        if (getOne(queryWrapper) != null || registerParam.getUsername().equals("admin")){
            return AjaxResult.error(2, "用户名已存在");
        }

        // 保存到数据库
        // 1.用户表
        User user = new User();
        user.setUsername(registerParam.getUsername());
        // 密码bcrypt加密存储
        String bcryptPassword = passwordEncoder.encode(registerParam.getPassword());
        user.setPasswordBcrypt(bcryptPassword);
        save(user);

        // 2. 角色表-暂定只能注册普通员工-employee
        //todo 使用雪花算法id
        // 获取id
        User userForId = getOne(queryWrapper);
        LambdaQueryWrapper<Role> roleQueryWrapper = new LambdaQueryWrapper<>();
        roleQueryWrapper
                .eq(Role::getRole, "employee");
        Role roleForId = roleService.getOne(roleQueryWrapper);

        // 3. 角色-用户表
        UserRole userRole = new UserRole();
        userRole.setUserId(userForId.getUserId());
        userRole.setRoleId(roleForId.getRoleId());
        userRoleService.save(userRole);

        return AjaxResult.success();
    }

    // todo 命名不对，应该is开头
    private boolean checkFormat(String username, String password){
        // todo 验证用户名 密码格式
        return true;
    }
}




